home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / Picture Viewer / Source / PictureViewerUtils.cpp < prev    next >
Encoding:
Text File  |  1995-12-08  |  24.7 KB  |  879 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2.     File:        PictureViewerUtils.cpp
  3.     
  4.     Contains:    Implementation of utility routines and classes.
  5.  
  6.     Written by:    Sue Dumont        [based on SamplePart by Steve Smith]
  7.  
  8.     Copyright:    © 1994-95 by Apple Computer, Inc., all rights reserved.
  9. ------------------------------------------------------------------------------*/
  10.  
  11. // -- Compiler/Preprocessor Switches --
  12.  
  13. #ifndef _COMPILERDEFS_
  14. #include "CompDefs.h"
  15. #endif
  16.  
  17. // -- OpenDoc Utilities --
  18.  
  19. #ifndef _EXCEPT_
  20. // Exceptions define several important macros (eg. CHECKENV)
  21. // which are used in the SOM method dispatch glue. If Except.h
  22. // is not included early enough, exceptions may not be thrown
  23. // correctly when returning from a SOM method with the "ev" parameter set.
  24. #include <Except.h>
  25. #endif
  26.  
  27. // --- PictureViewer Includes ---
  28.  
  29. #ifndef _PICTUREVIEWERUTILS_
  30. #include "PictureViewerUtils.h"
  31. #endif
  32.  
  33. #ifndef _PICTUREVIEWERDEF_
  34. #include "PictureViewerDef.h"
  35. #endif
  36.  
  37. // --- OpenDoc Includes ---
  38.  
  39. #ifndef _ODTYPES_
  40. #include <ODTypes.h>
  41. #endif
  42.  
  43. #ifndef SOM_ODCanvas_xh
  44. #include <Canvas.xh>
  45. #endif
  46.  
  47. #ifndef SOM_ODDraft_xh
  48. #include <Draft.xh>
  49. #endif
  50.  
  51. #ifndef SOM_ODFacet_xh
  52. #include <Facet.xh>
  53. #endif
  54.  
  55. #ifndef SOM_ODFrame_xh
  56. #include <Frame.xh>
  57. #endif
  58.  
  59. #ifndef SOM_ODFrameFacetIterator_xh
  60. #include <FrFaItr.xh>
  61. #endif
  62.  
  63. #ifndef SOM_ODSession_xh
  64. #include <ODSessn.xh>
  65. #endif
  66.  
  67. #ifndef SOM_Module_OpenDoc_StdProps_defined
  68. #include <StdProps.xh>
  69. #endif
  70.  
  71. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  72. #include <StdTypes.xh>
  73. #endif
  74.  
  75. #ifndef SOM_ODStorageUnit_xh
  76. #include <StorageU.xh>
  77. #endif
  78.  
  79. #ifndef SOM_ODStorageUnitView_xh
  80. #include <SUView.xh>
  81. #endif
  82.  
  83. #ifndef SOM_ODDocument_xh
  84. #include <Document.xh>
  85. #endif
  86.  
  87. #ifndef SOM_ODContainer_xh
  88. #include <ODCtr.xh>
  89. #endif
  90.  
  91. #ifndef SOM_ODNameSpaceManager_xh
  92. #include <NmSpcMg.xh>
  93. #endif
  94.  
  95. #ifndef SOM_ODValueNameSpace_xh
  96. #include <ValueNS.xh>
  97. #endif
  98.  
  99. #ifndef SOM_ODWindowState_xh
  100. #include <WinStat.xh>
  101. #endif
  102.  
  103. // -- OpenDoc Utilities --
  104.  
  105. #ifndef _BNDNSUTL_
  106. #include <BndNSUtl.h>
  107. #endif
  108.  
  109. #ifndef _DOCUTILS_
  110. #include <DocUtils.h>
  111. #endif
  112.  
  113. #ifndef _ODDEBUG_
  114. #include <ODDebug.h>
  115. #endif
  116.  
  117. #ifndef _ISOSTR_
  118. #include "ISOStr.h"
  119. #endif
  120.  
  121. #ifndef _STDTYPIO_
  122. #include <StdTypIO.h>
  123. #endif
  124.  
  125. #ifndef _STORUTIL_
  126. #include <StorUtil.h>
  127. #endif
  128.  
  129. #ifndef _TEMPOBJ_
  130. #include <TempObj.h>
  131. #endif
  132.  
  133. #ifndef _TEMPITER_
  134. #include <TempIter.h>
  135. #endif
  136.  
  137. #ifndef _USERSRCM_
  138. #include <UseRsrcM.h>
  139. #endif
  140.  
  141. // --- Macintosh Includes ---
  142.  
  143. #ifndef __RESOURCES__
  144. #include <Resources.h>
  145. #endif
  146.  
  147. #ifndef __GXMATH__
  148. #include <GXMath.h>
  149. #endif
  150.  
  151. #ifndef __SCRIPT__
  152. #include <Script.h>
  153. #endif
  154.  
  155. #ifndef __TEXTUTILS__
  156. #include <TextUtils.h>
  157. #endif
  158.  
  159.  
  160. #pragma segment PictureViewerUtilities
  161.  
  162. //====================================================================
  163. // Utility Functions
  164. //====================================================================
  165.  
  166. //--------------------------------------------------------------------
  167. // GetPartName
  168. //--------------------------------------------------------------------
  169. ODIText* GetPartName(Environment* ev, ODPart* part, ODType category)
  170. {
  171.     ASSERT(part != kODNULL, kODErrIllegalNullPartInput);
  172.  
  173.     // Get the root part of the document.
  174.     ODDraft* draft = ODGetDraft(ev,part);
  175.     TempODPart rootPart = ODAcquireRootPartOfDraft(ev, draft);
  176.     
  177.     // Get the part name.
  178.     // If we can't get a valid name for the part, we generate one using
  179.     // the user visible category name of the part's category.
  180.     TempODIText partName = ODGetITextProp(ev, part->GetStorageUnit(ev), 
  181.                                          kODPropName, kODMacIText, kODNULL);
  182.     
  183.     // If the part is the root of the document, return the name of the file.
  184.     if ( ODObjectsAreEqual(ev, part, rootPart) )
  185.     {
  186.         ODContainer* container = draft->GetDocument(ev)->GetContainer(ev);
  187.         TempPlatformFile file = GetPlatformFileFromContainer(ev, container);
  188.  
  189.         TempODIText fileName = file->GetName();
  190.         
  191.         // Test the file name against the part name. If the two are equivalent
  192.         // (not equal), then use the part name.
  193.         if ( !NamesAreEquivalent(ev, fileName, partName) )
  194.         {
  195.             // If the names are different, return the file name.
  196.             // (This code transfers the ODIText object to the partName tempobj)
  197.             DisposeIText(partName.DontDelete());
  198.             partName = fileName.DontDelete();
  199.         }
  200.     }
  201.     else
  202.     {
  203.         if ( (partName == kODNULL) || (GetITextStringLength(partName) == 0) )
  204.         {
  205.             ODIText* categoryName;
  206.             ODNameSpaceManager* nsMgr = ODGetSession(ev,part)->GetNameSpaceManager(ev);
  207.             
  208.             // Get the category string from the category name space.
  209.             if ( GetUserCatFromCat(nsMgr, category, &categoryName) )
  210.             {
  211.                 // If we successfully retrieved the category user string, return it.
  212.                 // (This code transfers the ODIText object to the partName tempobj)
  213.                 DisposeIText(partName.DontDelete());
  214.                 partName = categoryName;
  215.             }
  216.             else
  217.             {
  218.     #if ODDebug
  219.                 // This should never happen. Check NMAP for errors.
  220.                 DebugStr("\pCategory NMAP bad, or Preferences corrupted.");
  221.     #else
  222.                 THROW(kODErrInvalidNSType);
  223.     #endif
  224.             }
  225.         }
  226.     }
  227.     
  228.     return partName.DontDelete();
  229. }
  230.  
  231. //--------------------------------------------------------------------
  232. // NamesAreEquivalent
  233. //--------------------------------------------------------------------
  234. ODBoolean NamesAreEquivalent(Environment* ev, ODIText* fileName,
  235.                                         ODIText* partName)
  236. {
  237.     Str255 fileStr;
  238.     Str255 partStr;
  239.     
  240.     // If the strings are in different languages, we're done.
  241.     if ( (GetITextScriptCode(fileName) != GetITextScriptCode(partName)) ||
  242.             GetITextLangCode(fileName) != GetITextLangCode(partName) )
  243.         return kODFalse;
  244.     
  245.     GetITextPString(fileName, fileStr);
  246.     GetITextPString(partName, partStr);
  247.  
  248.     // If the string lengths are different, we're done.
  249.     if ( fileStr[0] != partStr[0] )
  250.         return kODFalse;
  251.  
  252.     // Return the Toolbox string equivalence test.
  253.     return EqualString(fileStr,partStr,kODTrue,kODTrue);
  254. }
  255.  
  256. //--------------------------------------------------------------------
  257. // GetEditorScriptLanguage
  258. //--------------------------------------------------------------------
  259. void GetEditorScriptLanguage(Environment* ev, ODScriptCode* script,
  260.                                         ODLangCode* language)
  261. {
  262.     long        region;
  263.     ODSLong        savedRefNum;
  264.     
  265.     savedRefNum = BeginUsingLibraryResources();
  266.     {
  267.         Handle versHdl = Get1Resource('vers', 1);
  268.         
  269.         // Get the region code of the editor/viewer, otherwise
  270.         // use the region code the of the primary system script.
  271.         
  272.         if ( versHdl )
  273.         {
  274.             region = (long)(*(VersRecHndl)versHdl)->countryCode;
  275.             ReleaseResource(versHdl);
  276.         }
  277.         else
  278.         {
  279.             region = GetScriptManagerVariable(smRegionCode);
  280.         }
  281.         
  282.         // Spanish & Japanese are not actually supported by this viewer.
  283.         // They are provided as examples of how to add recognition of
  284.         // additional regions (see Script.h for region codes).
  285.         
  286.         switch ((short)region) {
  287.             case verUS:
  288.                 *script = smRoman;
  289.                 *language = langEnglish;
  290.                 break;
  291.             case verSpain:
  292.                 *script = smRoman;
  293.                 *language = langSpanish;
  294.                 break;
  295.             case verJapan:
  296.                 *script = smJapanese;
  297.                 *language = langJapanese;
  298.                 break;
  299.             default:
  300.                 *script = smRoman;
  301.                 *language = langEnglish;
  302.         }                
  303.     }
  304.     EndUsingLibraryResources(savedRefNum);
  305. }
  306.  
  307. //--------------------------------------------------------------------
  308. // BeginGWorldThumbnail
  309. //--------------------------------------------------------------------
  310. GWorldPtr BeginGWorldThumbnail(CGrafPtr* savePort, GDHandle* saveGDevice)
  311. {
  312.     GWorldPtr    gwPtr;
  313.     Rect        bounds;
  314.     
  315.     ODVolatile(gwPtr);
  316.     
  317.     TRY
  318.         // Save window's graphics port and device
  319.         GetGWorld(savePort, saveGDevice);
  320.         
  321.         // Set the bounds rect to enclose the 64x64 thumbnail.
  322.         SetRect(&bounds, 0, 0, kODThumbnailSize, kODThumbnailSize);
  323.         
  324.         // Create offscreen GWorld
  325.         THROW_IF_ERROR( NewGWorld(&gwPtr, 0, &bounds, 0, 0, useTempMem) );
  326.     
  327.         SetGWorld(gwPtr, nil);
  328.             
  329.         // Initialize the pixel image
  330.         EraseRect(&gwPtr->portRect);
  331.  
  332.     CATCH_ALL
  333.         DisposeGWorld(gwPtr);
  334.         gwPtr = kODNULL;
  335.     ENDTRY
  336.  
  337.     return gwPtr;
  338. }
  339.  
  340. //--------------------------------------------------------------------
  341. // EndGWorldThumbnail
  342. //--------------------------------------------------------------------
  343. void EndGWorldThumbnail(CGrafPtr savePort, GDHandle saveGDevice)
  344. {
  345.     SetGWorld(savePort, saveGDevice);
  346. }
  347.  
  348. //--------------------------------------------------------------------
  349. // DrawGWorldThumbnail
  350. //--------------------------------------------------------------------
  351. void DrawGWorldThumbnail(Environment* ev, GWorldPtr gwPtr, ODFacet* facet)
  352. {
  353.     GrafPtr            thePort;
  354.     Rect            bounds;
  355.         
  356.     if ( gwPtr )
  357.     {
  358.         SetRect(&bounds, 0, 0, kODThumbnailSize, kODThumbnailSize);
  359.         thePort = facet->GetCanvas(ev)->GetQDPort(ev);
  360.  
  361.         if ( LockPixels( GetGWorldPixMap(gwPtr) ) )
  362.         {
  363.             CopyBits(&((GrafPtr)gwPtr)->portBits, &thePort->portBits,
  364.                                 &bounds, &bounds, srcCopy, nil);
  365.             UnlockPixels( GetGWorldPixMap(gwPtr) );
  366.         }
  367.     }
  368. }
  369.  
  370. //-------------------------------------------------------------------------
  371. // Read1IndResource
  372. //-------------------------------------------------------------------------
  373.  
  374. ODHandle Read1IndResource(ResType type, short index)
  375. {
  376.     // This routine will read a resource in from the current resource
  377.     // file and into temporary memory rather than the application heap.
  378.     // The ODReadResource routine couldn't be used because it reads a
  379.     // resource from the editor's resource fork, not the current file's,
  380.     // but the code here was stolen liberally from that routine.
  381.  
  382.     ODHandle result = kODNULL; 
  383.     ODVolatile(result);
  384.     
  385.     SetResLoad(false);
  386.     Handle rsrc = Get1IndResource(type, index);
  387.     SetResLoad(true);
  388.     
  389.     if ( rsrc == kODNULL ) 
  390.     {
  391.         OSErr err = ResError();
  392.         THROW(err ? err : resNotFound);
  393.     }
  394.     
  395.     TRY
  396.         ODSize size = (*rsrc) ? GetHandleSize(rsrc) : GetResourceSizeOnDisk(rsrc);
  397.  
  398.         result = ODNewHandle(size);
  399.         void* dst = ODLockHandle(result);
  400.         
  401.         if ( *rsrc == kODNULL ) 
  402.         {
  403.             // Resource is not in memory, use partial-resource call:
  404.             ReadPartialResource(rsrc, 0, dst, size);
  405.             THROW_IF_ERROR(ResError());
  406.             ReleaseResource(rsrc);
  407.         } 
  408.         else 
  409.         {
  410.             // Resource is already in memory; just copy it:
  411.             ODBlockMove(*rsrc, dst, size);
  412.         }
  413.  
  414.         ODUnlockHandle(result);
  415.     CATCH_ALL
  416.         if ( *rsrc == kODNULL )
  417.             ReleaseResource(rsrc);
  418.         if ( result )
  419.             ODDisposeHandle(result);
  420.         RERAISE;
  421.     ENDTRY
  422.     
  423.     return result;
  424. }
  425.  
  426. //--------------------------------------------------------------------
  427. // FixedToIntRect
  428. //--------------------------------------------------------------------
  429. void FixedToIntRect(ODRect& fixedRect, Rect& intRect)
  430. {
  431.     intRect.top        = FixedToInt(fixedRect.top);
  432.     intRect.left    = FixedToInt(fixedRect.left);
  433.     intRect.bottom    = FixedToInt(fixedRect.bottom);
  434.     intRect.right    = FixedToInt(fixedRect.right);
  435. }
  436.  
  437. //--------------------------------------------------------------------
  438. // IntToFixedRect
  439. //--------------------------------------------------------------------
  440.  
  441. void IntToFixedRect(Rect& intRect, ODRect& fixedRect)
  442. {
  443.     fixedRect.left        = ff(intRect.left);
  444.     fixedRect.top        = ff(intRect.top);
  445.     fixedRect.right        = ff(intRect.right);
  446.     fixedRect.bottom    = ff(intRect.bottom);
  447. }
  448.  
  449. //--------------------------------------------------------------------
  450. // TilePartWindow
  451. //--------------------------------------------------------------------
  452. Rect TilePartWindow(Environment* ev, Rect* facetBounds, Rect* partWindowBounds)
  453. {
  454.     const short    kWindowTilingConst    = 20;
  455.     const short kLeftToRight        = 0;
  456.     const short kRightToLeft        = -1;
  457.     
  458.     short direction;
  459.     
  460.     // Get the direction for the primary script system running on this machine.
  461.     // (Right-to-Left or Left-to-Right)
  462.     direction = GetSysDirection();
  463.     
  464.     // The child window should be tiled from the topLeft corner of the 
  465.     // active facet whose frame is being opened.
  466.     if ( direction == kLeftToRight )
  467.     {
  468.         // Position the window rect at the top/left corner of the facet.
  469.         OffsetRect(partWindowBounds, facetBounds->left, facetBounds->top);
  470.         // Now tile the window rect down and to the right.
  471.         OffsetRect(partWindowBounds, kWindowTilingConst, kWindowTilingConst);
  472.     }
  473.     // The child window should be tiled from the topRight corner of the 
  474.     // active facet whose frame is being opened.
  475.     else if ( direction == kRightToLeft )
  476.     {
  477.         // Position the window rect at the top/right corner of the facet.
  478.         OffsetRect(partWindowBounds, (partWindowBounds->right - facetBounds->right),
  479.                     facetBounds->top);
  480.         // Now tile the window rect down and to the left.
  481.         OffsetRect(partWindowBounds, -kWindowTilingConst, kWindowTilingConst);
  482.     }
  483.     
  484.     return *partWindowBounds;
  485. }
  486.  
  487. //--------------------------------------------------------------------
  488. // CountFacets
  489. //--------------------------------------------------------------------
  490. ODUShort CountFacets(Environment* ev, ODFrame* frame)
  491. {
  492.     ODUShort facetCount = 0;
  493.     ODFacet* facet;
  494.     
  495.     TempODFrameFacetIterator ffiter(ev, frame);
  496.     facet = ffiter.First();
  497.     while ( ffiter.IsNotComplete() )
  498.     {
  499.         facetCount++;
  500.         facet = ffiter.Next();
  501.     }
  502.     
  503.     return facetCount;
  504. }
  505.  
  506. //=========================================================================
  507. // CFrameProxy
  508. //=========================================================================
  509.  
  510. //-------------------------------------------------------------------------
  511. // CFrameProxy::SetFrame
  512. //
  513. // The code will not affect the proxy fields unless it can successfully
  514. // acquire the incoming frame, its id, and the draft the frame lives in.
  515. // If something goes wrong, the proxy remains unchanged.
  516. //-------------------------------------------------------------------------
  517. void CFrameProxy::SetFrame(Environment* ev, ODFrame* frame)
  518. {
  519.     ASSERT(frame!=kODNULL, kODErrIllegalNullFrameInput);
  520.     
  521.     ODID id;
  522.     ODDraft* draft;
  523.     
  524.     // Using the temp object will cleanup the incoming
  525.     // frame's refcount if something goes wrong.
  526.     frame->Acquire(ev);
  527.     TempODFrame tFrame = frame;
  528.     
  529.     // Perform all the operations that can fail, first.
  530.     TempODPart tPart = frame->AcquirePart(ev);
  531.     id = frame->GetID(ev);
  532.     draft = ODGetDraft(ev, tPart);
  533.     ODReleaseObject(ev, fFrame);
  534.  
  535.     // If all went well, set the proxy fields.
  536.     fFrame = tFrame.DontRelease();
  537.     fID = id;
  538.     fDraft = draft;
  539. }
  540.  
  541. //-------------------------------------------------------------------------
  542. // CFrameProxy::GetFrame
  543. //-------------------------------------------------------------------------
  544. ODFrame* CFrameProxy::GetFrame(Environment* ev)
  545. {
  546.     if ( fFrame == kODNULL )
  547.     {
  548.         TRY
  549.             TempODFrame frame = fDraft->AcquireFrame(ev, fID);
  550.             this->SetFrame(ev, frame);
  551.         CATCH_ALL
  552.             fFrame = kODNULL;
  553.             fID = kODNULLID;
  554.         ENDTRY
  555.     }
  556.     return fFrame;
  557. }
  558.  
  559. //-------------------------------------------------------------------------
  560. // CFrameProxy::FrameIsLoaded
  561. //-------------------------------------------------------------------------
  562. ODBoolean CFrameProxy::FrameIsLoaded(Environment* ev)
  563. {
  564.     ODBoolean loaded = (fFrame != kODNULL ||
  565.                         fDraft->IsValidID(ev, fID));
  566.     return loaded;
  567. }
  568.  
  569. //-------------------------------------------------------------------------
  570. // CFrameProxy::Purge
  571. //-------------------------------------------------------------------------
  572. void CFrameProxy::Purge(Environment* ev)
  573. {
  574.     if ( fFrame != kODNULL )
  575.     {
  576.         fID = fFrame->GetID(ev);
  577.         ODReleaseObject(ev, fFrame);
  578.     }
  579. }
  580.  
  581. //=========================================================================
  582. // CFrameInfo
  583. //=========================================================================
  584.  
  585. //-------------------------------------------------------------------------
  586. // CFrameInfo::CFrameInfo
  587. //-------------------------------------------------------------------------
  588.  
  589. CFrameInfo::CFrameInfo(ODSession* session)
  590. {
  591.     fSession = session;
  592.     fFrameActive = kODFalse;
  593.     fFrameReactivate  = kODFalse;
  594.     fShouldDisposeWindow = kODFalse;
  595.     fIsNegotiated = kODFalse;
  596.     fActiveFacet = kODNULL;
  597.     fSourceFrame = kODNULL;
  598.     fDependentFrame = kODNULL;
  599.     fPartWindowID = kODNULLID; 
  600. }
  601.  
  602. //-------------------------------------------------------------------------
  603. // CFrameInfo::~CFrameInfo
  604. //-------------------------------------------------------------------------
  605. CFrameInfo::~CFrameInfo()
  606. {
  607.     // Deleting the proxies will release the encapsulated frames.
  608.     ODDeleteObject(fDependentFrame);
  609.     ODDeleteObject(fSourceFrame);
  610. }
  611.  
  612. //-------------------------------------------------------------------------
  613. // CFrameInfo::Externalize
  614. //-------------------------------------------------------------------------
  615. void CFrameInfo::Externalize(Environment* ev, ODStorageUnitView* storageUnitView)
  616. {
  617.     // This method assumes that OpenDoc has passed us a storageUnitView
  618.     // that is focused to a property, but no particular value.
  619.     
  620.     ODStorageUnit* storageUnit = storageUnitView->GetStorageUnit(ev);
  621.  
  622.     this->CleanseFrameInfoProperty(ev, storageUnit);
  623.     this->ExternalizeFrameInfo(ev, storageUnit, kODNULLKey, kODNULL);
  624. }
  625.  
  626. //-------------------------------------------------------------------------
  627. // CFrameInfo::CleanseFrameInfoProperty
  628. //-------------------------------------------------------------------------
  629. void CFrameInfo::CleanseFrameInfoProperty(Environment* ev, ODStorageUnit* storageUnit)
  630. {
  631.     ODULong numValues;
  632.     ODULong index;
  633.         
  634.     numValues = storageUnit->CountValues(ev);
  635.     
  636.     for (index = numValues; index >= 1; index--)
  637.     {
  638.         // Index, from 1 to n, through the values.
  639.         storageUnit->Focus(ev, kODNULL, kODPosSame, 
  640.                                 kODNULL, index, kODPosUndefined);
  641.                                 
  642.         // Get the ISO type name for the value. The temp object
  643.         // will automatically delete the returned value when this
  644.         // scope is exited.
  645.         TempODValueType value = storageUnit->GetType(ev);
  646.         
  647.         // If the value type is not one we support, remove it.
  648.         if ( !ODISOStrEqual(value, kPictureViewerInfo) )
  649.             storageUnit->Remove(ev);
  650.     }
  651. }
  652.  
  653. //-------------------------------------------------------------------------
  654. // CFrameInfo::ExternalizeFrameInfo
  655. //-------------------------------------------------------------------------
  656. void CFrameInfo::ExternalizeFrameInfo(Environment* ev, ODStorageUnit* storageUnit,
  657.                                         ODDraftKey key, ODFrame* scopeFrame)
  658. {
  659.     // This method behaves much the same way as the SamplePart::ExternalizeStateInfo
  660.     // method.
  661.     
  662.     if ( storageUnit->Exists(ev, kODNULL, kPictureViewerInfo, 0) )
  663.     {
  664.         // Persistent object references are stored in a side table, rather than
  665.         // in the property/value stream. Thus, deleting the contents of a value
  666.         // will not "delete" the references previously written to that value. To
  667.         // completely "delete" all references written to the value, we must
  668.         // remove the value and add it back.
  669.  
  670.         storageUnit->Focus(ev, kODNULL, kODPosSame, kPictureViewerInfo, 0, kODPosUndefined);
  671.         storageUnit->Remove(ev);
  672.     }
  673.  
  674.     // Add a value to write the data into.
  675.     storageUnit->AddValue(ev, kPictureViewerInfo);
  676.     
  677.     {
  678.         // Write a weak reference to our source frame.
  679.         ODStorageUnitRef weakRef = {0,0,0,0};
  680.     
  681.         if ( fSourceFrame )
  682.         {
  683.             ODID        frameID = fSourceFrame->GetID();
  684.             ODID        scopeFrameID = ( scopeFrame ? scopeFrame->GetID(ev) : kODNULLID );
  685.             ODDraft*    fromDraft = fSourceFrame->GetDraft();
  686.     
  687.             // If a draft key exists, then we are being cloned to another draft.
  688.             // We must "weak" clone our display frame and reference the cloned
  689.             // frame. The part re-uses the frameID variable so there aren't two
  690.             // different GetWeakStorageUnitRef calls.
  691.             if ( key )
  692.                 frameID = fromDraft->WeakClone(ev, key, frameID, kODNULLID, scopeFrameID);
  693.             
  694.             // Write out weak references to each of the part's display frames.
  695.             storageUnit->GetWeakStorageUnitRef(ev, frameID, weakRef);
  696.         }
  697.         StorageUnitSetValue(storageUnit, ev, sizeof(ODStorageUnitRef), (ODPtr)&weakRef);
  698.     }
  699.     
  700.     {
  701.         // Write a weak reference to our dependent frame.
  702.         ODStorageUnitRef weakRef = {0,0,0,0};
  703.  
  704.         if ( fDependentFrame )
  705.         {
  706.             ODID        frameID = fDependentFrame->GetID();
  707.             ODID        scopeFrameID = ( scopeFrame ? scopeFrame->GetID(ev) : kODNULLID );
  708.             ODDraft*    fromDraft = fDependentFrame->GetDraft();
  709.     
  710.             // If a draft key exists, then we are being cloned to another draft.
  711.             // We must "weak" clone our display frame and reference the cloned
  712.             // frame. The part re-uses the frameID variable so there aren't two
  713.             // different GetWeakStorageUnitRef calls.
  714.             if ( key )
  715.                 frameID = fromDraft->WeakClone(ev, key, frameID, kODNULLID, scopeFrameID);
  716.             
  717.             // Write out weak references to each of the part's display frames.
  718.             storageUnit->GetWeakStorageUnitRef(ev, frameID, weakRef);
  719.         }
  720.         StorageUnitSetValue(storageUnit, ev, sizeof(ODStorageUnitRef), (ODPtr)&weakRef);
  721.     }
  722. }
  723.  
  724. //-------------------------------------------------------------------------
  725. // CFrameInfo::CloneInto
  726. //-------------------------------------------------------------------------
  727. void CFrameInfo::CloneInto(Environment *ev, ODDraftKey key,
  728.                             ODStorageUnitView* storageUnitView, ODFrame* scopeFrame)
  729. {
  730.     // This method assumes that OpenDoc has passed us a storageUnitView
  731.     // that is focused to a property, but no particular value.
  732.     
  733.     ODStorageUnit* storageUnit = storageUnitView->GetStorageUnit(ev);
  734.  
  735.     if ( storageUnit->Exists(ev, kODNULL, kPictureViewerInfo, 0) == kODFalse )
  736.     {
  737.         this->ExternalizeFrameInfo(ev, storageUnit, key, scopeFrame);
  738.     }
  739. }
  740.  
  741. //-------------------------------------------------------------------------
  742. // CFrameInfo::InitFromStorage
  743. //------------------------------------------------------------------------------
  744. void CFrameInfo::InitFromStorage(Environment* ev, ODStorageUnitView* storageUnitView)
  745. {
  746.     // This method assumes that OpenDoc has passed us a storageUnitView
  747.     // that is focused to a property, but no particular value.
  748.     
  749.     ODStorageUnit* storageUnit = storageUnitView->GetStorageUnit(ev);
  750.  
  751.     if ( storageUnit->Exists(ev, kODNULL, kPictureViewerInfo, 0) )
  752.     {
  753.         TRY
  754.             storageUnit->Focus(ev, kODNULL, kODPosSame,
  755.                                         kPictureViewerInfo, 0 , kODPosUndefined);
  756.     
  757.             ODStorageUnitRef weakRef = {0,0,0,0};
  758.             StorageUnitGetValue(storageUnit, ev, sizeof(ODStorageUnitRef),
  759.                                 (ODPtr)&weakRef);
  760.             
  761.             if ( storageUnit->IsValidStorageUnitRef(ev, weakRef) )
  762.             {
  763.                 // Convert the reference into a runtime id.
  764.                 ODID frameID = storageUnit->GetIDFromStorageUnitRef(ev, weakRef);
  765.  
  766.                 // Create a proxy class to support the lazy internalization.
  767.                 CFrameProxy* proxy = new CFrameProxy;
  768.                 proxy->InitFrameProxy(frameID, ODGetDraft(ev,storageUnit));
  769.  
  770.                 // Store the proxy source frame.
  771.                 fSourceFrame = proxy;
  772.             }
  773.             
  774.         CATCH_ALL
  775.             ODDeleteObject(fSourceFrame);
  776.             fSourceFrame = kODNULL;
  777.         ENDTRY
  778.  
  779.         TRY
  780.             ODStorageUnitRef weakRef = {0,0,0,0};
  781.             StorageUnitGetValue(storageUnit, ev, sizeof(ODStorageUnitRef),
  782.                                 (ODPtr)&weakRef);
  783.             
  784.             if ( storageUnit->IsValidStorageUnitRef(ev, weakRef) )
  785.             {
  786.                 // Convert the reference into a runtime id.
  787.                 ODID frameID = storageUnit->GetIDFromStorageUnitRef(ev, weakRef);
  788.  
  789.                 // Create a proxy class to support the lazy internalization.
  790.                 CFrameProxy* proxy = new CFrameProxy;
  791.                 proxy->InitFrameProxy(frameID, ODGetDraft(ev,storageUnit));
  792.  
  793.                 // Store the proxy dependent frame.
  794.                 fDependentFrame = proxy;
  795.             }
  796.             
  797.         CATCH_ALL
  798.             ODDeleteObject(fDependentFrame);
  799.             fDependentFrame = kODNULL;
  800.         ENDTRY
  801.     }
  802. }
  803.  
  804. //-------------------------------------------------------------------------
  805. // CFrameInfo::SetSourceFrame
  806. //-------------------------------------------------------------------------
  807. void CFrameInfo::SetSourceFrame(Environment* ev, ODFrame* frame)
  808. {
  809.     if ( frame != kODNULL )
  810.     {
  811.         // Create a proxy class to support the lazy internalization.
  812.         CFrameProxy* proxy = new CFrameProxy;
  813.         proxy->InitFrameProxy(ev, frame);
  814.         
  815.         // Store the proxy source frame after clearing the old one.
  816.         ODDeleteObject(fSourceFrame);
  817.         fSourceFrame = proxy;
  818.     }
  819. }
  820.  
  821. //-------------------------------------------------------------------------
  822. // CFrameInfo::ReleaseSourceFrame
  823. //-------------------------------------------------------------------------
  824. void CFrameInfo::ReleaseSourceFrame(Environment* ev)
  825. {
  826.     ODDeleteObject(fSourceFrame);
  827. }
  828.  
  829. //-------------------------------------------------------------------------
  830. // CFrameInfo::SetDependentFrame
  831. //-------------------------------------------------------------------------
  832. void CFrameInfo::SetDependentFrame(Environment* ev, ODFrame* frame)
  833. {
  834.     if ( frame != kODNULL )
  835.     {
  836.         // Create a proxy class to support the lazy internalization.
  837.         CFrameProxy* proxy = new CFrameProxy;
  838.         proxy->InitFrameProxy(ev, frame);
  839.         
  840.         // Store the proxy dependent frame after clearing the old one.
  841.         ODDeleteObject(fDependentFrame);
  842.         fDependentFrame = proxy;
  843.     }
  844. }
  845.  
  846. //-------------------------------------------------------------------------
  847. // CFrameInfo::ReleaseDependentFrame
  848. //-------------------------------------------------------------------------
  849. void CFrameInfo::ReleaseDependentFrame(Environment* ev)
  850. {
  851.     ODDeleteObject(fDependentFrame);
  852. }
  853.  
  854. //-------------------------------------------------------------------------
  855. // CFrameInfo::AcquirePartWindow
  856. //-------------------------------------------------------------------------
  857.  
  858. ODWindow* CFrameInfo::AcquirePartWindow(Environment* ev)
  859. {
  860.     ODWindow* window = kODNULL;
  861.     
  862.     if ( fPartWindowID )
  863.     {
  864.         window = fSession->GetWindowState(ev)->AcquireWindow(ev,fPartWindowID);
  865.         if ( !window) fPartWindowID = kODNULLID;
  866.     }
  867.     
  868.     return window;
  869. }
  870.  
  871. //-------------------------------------------------------------------------
  872. // CFrameInfo::SetPartWindow
  873. //-------------------------------------------------------------------------
  874.  
  875. void CFrameInfo::SetPartWindow(Environment* ev, ODWindow* window)
  876. {
  877.     fPartWindowID = window ? window->GetID(ev) : kODNULLID;
  878. }
  879.